<?php
namespace UHU\vCalendar;
require_once('vcalendar/parser.php');
interface parser_funcs
{
	public static function parse($data);
}
abstract class parser implements parser_funcs
{
	protected $calendar_pool;
	protected static function process(parser\vEvent & $event,parser\vEvent $data=null)
	{
		if(isset($data))
		{
			$destination_interfaces = static::filter_interfaces($event);
			$data_interfaces        = static::filter_interfaces($data);
			foreach($data_interfaces as $interface)
			{
				$property = substr($interface,strrpos($interface,'\\') + 1);
				$event->$property = $data->$property();
			}
		}
	}
	public static function bake_event_into_calendar(\UHU\microformats\hCalendar & $calendar,parser\vEvent_pub $event)
	{
		static $blank_event;
		if(isset($blank_event) === false)
		{
			$blank_event = new parser\vEvent_pub;
		}
		if($event != $blank_event)
		{
			$calendar[] = new parser\vEvent_baked($event);
		}
	}
	protected static function process_line($buffer,\UHU\microformats\hCalendar_pool & $calendar_pool,\UHU\microformats\hCalendar & $calendar=null,parser\vEvent_pub & $event=null,& $added_cal=false,& $added_event=false)
	{
		$buffer = trim($buffer);
		switch($buffer)
		{
			case 'BEGIN:VCALENDAR':
				if(isset($calendar) && $added_cal === false)
				{
					$calendar_pool[] = $calendar;
				}
				$calendar = new \UHU\microformats\hCalendar;
				$added_cal = false;
			break;
			case 'END:VCALENDAR':
				if(isset($calendar) && $added_cal === false)
				{
					$calendar_pool[] = $calendar;
					$calendar = null;
					$added_cal = true;
				}
			break;
			case 'BEGIN:VEVENT':
				if($calendar === null)
				{
					$calendar = new \UHU\microformats\hCalendar;
					$added_cal = false;
				}
				else
				{
					static::bake_event_into_calendar($calendar,$event);
					$added_event = true;
				}
				$event = new parser\vEvent_pub;
			break;
			case 'END:VEVENT':
				static::bake_event_into_calendar($calendar,$event);
				$added_event = true;
			break;
			default:
				static::process($event,static::parse_line($buffer));
			break;
		}
	}
	protected static function parse_line($data)
	{
		$d = explode(':',$data);
		$label = strtolower($d[0]);
		unset($d[0]);
		switch($label)
		{
			case 'uid':
			case 'dtstart':
			case 'dtend':
			case 'summary':
			case 'description':
			case 'category':
			case 'url':
				$data = implode(':',$d);
				switch($label)
				{
					case 'dtstart':
					case 'dtend':
						$data = new \UHU\moment($data);
					break;
				}
			break;
			default:
				return null;
			break;
		}
		$label = '\UHU\vCalendar\parser\vEvent\\_' . $label;
		return new $label($data);
	}
	protected static function filter_interfaces($object)
	{
		if(is_object($object) === false)
		{
			throw new \InvalidArgumentException('Only objects should passed as arguments.');
		}
		$interfaces = class_implements($object,false);
		foreach($interfaces as $k=>$interface)
		{
			if(strpos($interface,'UHU\microformats\hCalendar\\') !== 0)
			{
				unset($interfaces[$k]);
			}
		}
		return $interfaces;
	}
}
namespace UHU\vCalendar\parser;
class file extends \UHU\vCalendar\parser
{
	public static function parse($file)
	{
		if(is_string($file) === false)
		{
			throw new \InvalidArgumentException('Filename should be passed as string.');
		}
		else
		{
			try
			{
				$fp = fopen($file,'r');
				$fail = ($fp === false);
			}
			catch(Exception $e)
			{
				$fail = true;
			}
			if($fail)
			{
				throw new \RuntimeException('File could not be opened.',$e->getCode());
			}
			else
			{
				$calendar_pool = static::fp($fp);
				fclose($fp);
				return $calendar_pool;
			}
		}
	}
	protected static function fp($fp)
	{
		$calendar_pool = new \UHU\microformats\hCalendar_pool;
		$calendar    = null;
		$event       = new vEvent_pub;
		$added_cal   = false;
		$added_event = false;
		while(feof($fp) === false)
		{
			$buffer = fgets($fp);
			if(strlen(trim($buffer)) > 0)
			{
				static::process_line($buffer,$calendar_pool,$calendar,$event,$added_cal,$added_event);
			}
		}
		return $calendar_pool;
	}
}
class string extends file
{
	public static function parse($string)
	{
		try
		{
			$fail = ($fp = tmpfile()) === false;
		}
		catch(Exception $e)
		{
			$fail = $e->getCode();
		}
		if($fail !== false)
		{
			throw new \RuntimeException('Temporary file could not be created.',$fail);
		}
		else
		{
			try
			{
				$fail = (fwrite($fp,$string) === false);
				unset($string);
			}
			catch(Exception $e)
			{
				$fail = $e->getCode();
			}
			if($fail !== false)
			{
				throw new \RuntimeException('Could not write string to temporary file.',$fail);
			}
			else
			{
				try
				{
					$fail = (fseek($fp,0) === false);
				}
				catch(Exception $e)
				{
					$fail = $e->getCode();
				}
				if($fail !== false)
				{
					throw new \RuntimeException('Could not rewind file pointer to beginning of file.',$fail);
				}
				else
				{
					$calendar_pool = static::fp($fp);
					fclose($fp);
					return $calendar_pool;
				}
			}
		}
	}
}
class HTTP_PUT extends string
{
	public static function parse($data=null)
	{
		return parent::parse(file_get_contents('php://input'));
	}
}
?>